/**
 * @file app_central.c
 * @author Eker Cheng (yongfei.cheng@onmicro.com.cn)
 * @brief Application interface of central module
 * @version 1.0
 * @date 2022-03-09
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "rwapp_config.h"

#if (BLE_APP_CENTRAL_SUPPORT)

#include "att.h"
#include "co.h"
#include "co_utils.h"
#include "prf_utils.h"
#include "app.h"
#include "app_central.h"

#define APP_LOG_DOMAIN      "CENT"
#define APP_LOG_LEVEL       APP_CENTRAL_LOG_LEVEL
#include "app_log.h"

enum e_scan_todo
{
    SCAN_IDLE = 0,
    SCAN_START = 1,
    SCAN_STOP = 2,
};

#define CONN_SUPER_TIMEOUT          100 // 100 * 10ms

static scan_stopped_callback_t scan_stopped_callback;

/**
 * @brief Find connection information index that free
 * 
 * @return uint8_t : connection information index
 */
static uint8_t app_central_find_free(void)
{
    uint8_t i =0;
    for(i=0; i< BLE_APP_CENTRAL_SUPPORT; i++)
    {
        if (app_env.central.connect[i].state == APP_CENTRAL_SUB_STATE_IDLE)
            break;
    }
    return i;
}

/**
 * @brief Find connection information index of "actv_idx"
 * 
 * @return uint8_t : connection information index
 */
static uint8_t app_central_find_by_actv_idx(uint8_t actv_idx)
{
    uint8_t i =0;
    for(i=0; i< BLE_APP_CENTRAL_SUPPORT; i++)
    {
        if (app_env.central.connect[i].actv_idx == actv_idx)
            break;
    }
    return i;
}

/**
 * @brief Free the connection instance
 * 
 * @param index : connection information index
 */
static void app_central_free_node(uint8_t index)
{
    if (index >= BLE_APP_CENTRAL_SUPPORT)
        return;

    memset(&app_env.central.connect[index], 0, sizeof(struct app_central_node_tag));
    app_env.central.connect[index].conidx = 0xFF;
}

/**
 * @brief Create connection activity
 *          Send GAPM_ACTIVITY_CREATE_CMD message with GAPM_CREATE_INIT_ACTIVITY operation.
 * 
 * @param index: connection index
 */
static void app_central_create_init(uint8_t index)
{
    LOG_VBS_FUNC();

    struct gapm_activity_create_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_CREATE_CMD,
                                                          TASK_GAPM, TASK_APP,
                                                          gapm_activity_create_cmd);
    p_cmd->operation = GAPM_CREATE_INIT_ACTIVITY;
    p_cmd->own_addr_type = GAPM_STATIC_ADDR;
    ke_msg_send(p_cmd);

    app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_CREATING;
}

/**
 * @brief Delete connection activity
 *          Send GAPM_ACTIVITY_DELETE_CMD message with GAPM_DELETE_ACTIVITY operation.
 * 
 * @param index : connection index
 */
static void app_central_delete_init(uint8_t index)
{
    LOG_VBS_FUNC();

    struct gapm_activity_delete_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_DELETE_CMD,
                                                          TASK_GAPM, TASK_APP,
                                                          gapm_activity_delete_cmd);
    p_cmd->operation = GAPM_DELETE_ACTIVITY;
    p_cmd->actv_idx = app_env.central.connect[index].actv_idx;
    ke_msg_send(p_cmd);

    app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_DELETING;
}

/**
 * @brief Start connection activity
 *          Send GAPM_ACTIVITY_START_CMD message with GAPM_START_ACTIVITY operation.
 * 
 * @param index : connection index
 */
static void app_central_start_init(uint8_t index)
{
    LOG_VBS_FUNC();

    struct gapm_activity_start_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_START_CMD,
                                                         TASK_GAPM, TASK_APP,
                                                         gapm_activity_start_cmd);
    p_cmd->operation = GAPM_START_ACTIVITY;
    p_cmd->actv_idx = app_env.central.connect[index].actv_idx;

    /* 1M PHY scan parameters */
    p_cmd->u_param.init_param.scan_param_1m.scan_intv    = SCAN_INTERVAL_DFT;
    p_cmd->u_param.init_param.scan_param_1m.scan_wd      = SCAN_WINDOW_DFT;

    /* coded PHY scan parameters */
    p_cmd->u_param.init_param.scan_param_coded.scan_intv = SCAN_INTERVAL_DFT;
    p_cmd->u_param.init_param.scan_param_coded.scan_wd   = SCAN_WINDOW_DFT;

    p_cmd->u_param.init_param.type = GAPM_INIT_TYPE_DIRECT_CONN_EST;
    p_cmd->u_param.init_param.prop = GAPM_INIT_PROP_1M_BIT | GAPM_INIT_PROP_2M_BIT | GAPM_INIT_PROP_CODED_BIT;
    p_cmd->u_param.init_param.conn_to = 0; // 0 means no timeout

    /* 1M PHY connection parameters */
    p_cmd->u_param.init_param.conn_param_1m.conn_intv_min  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_1m.conn_intv_max  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_1m.conn_latency   = CON_LATENCY_MIN;
    p_cmd->u_param.init_param.conn_param_1m.supervision_to = CONN_SUPER_TIMEOUT;

    /* 2M PHY connection parameters */
    p_cmd->u_param.init_param.conn_param_2m.conn_intv_min  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_2m.conn_intv_max  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_2m.conn_latency   = CON_LATENCY_MIN;
    p_cmd->u_param.init_param.conn_param_2m.supervision_to = CONN_SUPER_TIMEOUT;

    /* Coded PHY connection parameters */
    p_cmd->u_param.init_param.conn_param_coded.conn_intv_min  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_coded.conn_intv_max  = CON_INTERVAL_MIN;
    p_cmd->u_param.init_param.conn_param_coded.conn_latency   = CON_LATENCY_MIN;
    p_cmd->u_param.init_param.conn_param_coded.supervision_to = CONN_SUPER_TIMEOUT;

    memcpy(&(p_cmd->u_param.init_param.peer_addr), &(app_env.central.connect[index].addr), sizeof(struct gap_bdaddr));

    ke_msg_send(p_cmd); // Send the message

    app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_STARTING;
}

/**
 * @brief Stop connection activity
 *          Send GAPM_ACTIVITY_STOP_CMD message with GAPM_STOP_ACTIVITY operation.
 * 
 * @param index : connection index
 */
static void app_central_stop_init(uint8_t index)
{
    LOG_VBS_FUNC();

    struct gapm_activity_stop_cmd *cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_STOP_CMD,
                                                      TASK_GAPM, TASK_APP,
                                                      gapm_activity_stop_cmd);
    cmd->operation = GAPM_STOP_ACTIVITY;
    cmd->actv_idx = app_env.central.connect[index].actv_idx;
    ke_msg_send(cmd);

    app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_STOPPING;
}

/**
 * @brief Create scan activity
 *          Send GAPM_ACTIVITY_CREATE_CMD message with GAPM_CREATE_SCAN_ACTIVITY operation.
 * 
 */
static void app_central_create_scan(void)
{
    LOG_VBS_FUNC();

    struct gapm_activity_create_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_CREATE_CMD,
                                                          TASK_GAPM, TASK_APP,
                                                          gapm_activity_create_cmd);
    p_cmd->operation = GAPM_CREATE_SCAN_ACTIVITY;
    p_cmd->own_addr_type = GAPM_STATIC_ADDR;
    ke_msg_send(p_cmd);

    app_env.central.scan_state = APP_CENTRAL_SUB_STATE_CREATING;
    app_env.central.scan_operation = GAPM_CREATE_SCAN_ACTIVITY;
}

/**
 * @brief Delele scan activity
 *          Send GAPM_ACTIVITY_DELETE_CMD message with GAPM_DELETE_ACTIVITY operation.
 * 
 */
static void app_central_delete_scan(void)
{
   LOG_VBS_FUNC();

   struct gapm_activity_delete_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_DELETE_CMD,
                                                         TASK_GAPM, TASK_APP,
                                                         gapm_activity_delete_cmd);
   p_cmd->operation = GAPM_DELETE_ACTIVITY;
   ke_msg_send(p_cmd);

   app_env.central.scan_state = APP_CENTRAL_SUB_STATE_DELETING;
}

/**
 * @brief Start scan activity
 *          Send GAPM_ACTIVITY_START_CMD message with GAPM_START_ACTIVITY operation.
 * 
 */
static void app_central_start_scan(void)
{
    LOG_VBS_FUNC();

    struct gapm_activity_start_cmd *p_cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_START_CMD,
                                                         TASK_GAPM, TASK_APP,
                                                         gapm_activity_start_cmd);
    p_cmd->operation = GAPM_START_ACTIVITY;
    p_cmd->actv_idx = app_env.central.scan_actv_idx;
    p_cmd->u_param.scan_param.type = GAPM_SCAN_TYPE_OBSERVER;
    p_cmd->u_param.scan_param.prop = GAPM_SCAN_PROP_PHY_1M_BIT|GAPM_SCAN_PROP_ACTIVE_1M_BIT|GAPM_SCAN_PROP_ACCEPT_RPA_BIT;
    p_cmd->u_param.scan_param.dup_filt_pol = GAPM_DUP_FILT_DIS;
    p_cmd->u_param.scan_param.scan_param_1m.scan_intv    = SCAN_INTERVAL_DFT;
    p_cmd->u_param.scan_param.scan_param_1m.scan_wd      = SCAN_WINDOW_DFT;
    p_cmd->u_param.scan_param.scan_param_coded.scan_intv = SCAN_INTERVAL_DFT;
    p_cmd->u_param.scan_param.scan_param_coded.scan_wd   = SCAN_WINDOW_DFT;
    p_cmd->u_param.scan_param.duration = 0;
    p_cmd->u_param.scan_param.period = 0;
    ke_msg_send(p_cmd);

    app_env.central.scan_state = APP_CENTRAL_SUB_STATE_STARTING;
    app_env.central.scan_operation = GAPM_START_ACTIVITY;
}

/**
 * @brief Stop scan activity
 *          Send GAPM_ACTIVITY_STOP_CMD message with GAPM_STOP_ACTIVITY operation.
 * 
 */
static void app_central_stop_scan(void)
{
    LOG_VBS_FUNC();

    struct gapm_activity_stop_cmd *cmd = KE_MSG_ALLOC(GAPM_ACTIVITY_STOP_CMD,
                                                      TASK_GAPM, TASK_APP,
                                                      gapm_activity_stop_cmd);
    cmd->operation = GAPM_STOP_ACTIVITY;
    cmd->actv_idx = app_env.central.scan_actv_idx;

    ke_msg_send(cmd);

    app_env.central.scan_state = APP_CENTRAL_SUB_STATE_STOPPING;
    app_env.central.scan_operation = GAPM_STOP_ACTIVITY;
}

/**
 * @brief Update scan state
 * 
 * @param opera    : operation type - GAPM_CREATE_SCAN_ACTIVITY / GAPM_DELETE_ACTIVITY /
 *                              GAPM_START_ACTIVITY / GAPM_STOP_ACTIVITY
 * @param actv_idx : activity index
 * @param reason   : operation result reason
 */
static void app_central_update_scan_state(uint8_t opera, uint8_t actv_idx, uint8_t reason)
{
    LOG_VBS_FUNC();

    (void)opera;
    LOG_DBG("scan state=%x, todo=%x, reason=%x", app_env.central.scan_state, app_env.central.scan_todo, reason);
    switch(app_env.central.scan_state)
    {
        case APP_CENTRAL_SUB_STATE_IDLE:
            break;

        case APP_CENTRAL_SUB_STATE_CREATING:
        {
            app_env.central.scan_actv_idx = actv_idx;
            app_env.central.scan_state = APP_CENTRAL_SUB_STATE_CREATED;
        } break;

        case APP_CENTRAL_SUB_STATE_CREATED:
        {
            if (reason != 0)
            {
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_IDLE;
                app_env.central.scan_todo = SCAN_IDLE;
                LOG_ERR("Scan error, reason: %d", reason);
            }
            else if (app_env.central.scan_todo != SCAN_STOP)
            {
                app_central_start_scan();
            }
        } break;

        case APP_CENTRAL_SUB_STATE_STARTING:
        {
            if (reason != 0)
            {
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_IDLE;
                app_env.central.scan_todo = SCAN_IDLE;
                LOG_ERR("Scan error, reason: %d", reason);
            }
            else if (app_env.central.scan_todo == SCAN_STOP)
            {
                app_central_stop_scan();
            }
            else
            {
                LOG_INF("Scan started.");
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_STARTED;
                app_env.central.scan_todo = SCAN_IDLE;
            }
        } break;

        case APP_CENTRAL_SUB_STATE_STARTED:
        if (reason != 0)
        {
            app_env.central.scan_state = APP_CENTRAL_SUB_STATE_CREATED;
            app_env.central.scan_todo = SCAN_IDLE;
        } break;

        case APP_CENTRAL_SUB_STATE_STOPPING:
        {
            if (app_env.central.scan_todo == SCAN_START)
            {
                app_env.central.scan_todo = SCAN_IDLE;
                app_central_start_scan();
            }
            else
            {
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_STOPPED;
            }
        } break;

        case APP_CENTRAL_SUB_STATE_STOPPED:
        {
            if (reason != 0)
            {
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_IDLE;
                app_env.central.scan_todo = SCAN_IDLE;
                LOG_ERR("Scan error, reason: %d", reason);
            }
            else if (app_env.central.scan_todo == SCAN_START)
            {
                app_env.central.scan_todo = SCAN_IDLE;
                app_central_start_scan();
            }
            else
            {
                LOG_INF("Scan stopped.");
                app_env.central.scan_state = APP_CENTRAL_SUB_STATE_CREATED;
                if (scan_stopped_callback != NULL)
                {
                    scan_stopped_callback();
                }
            }
        } break;

        default:
            break;
    }
}

/**
 * @brief Update connection state
 * 
 * @param opera    : operation type - GAPM_CREATE_INIT_ACTIVITY / GAPM_DELETE_ACTIVITY /
 *                              GAPM_START_ACTIVITY / GAPM_STOP_ACTIVITY
 * @param actv_idx : activity index
 * @param reason   : operation result reason
 */
static void app_central_update_init_state(uint8_t opera, uint8_t actv_idx, uint8_t reason)
{
    LOG_VBS_FUNC();
    LOG_DBG("%x,%x,%x,%x", opera, actv_idx, reason, app_env.central.w4connect);

    uint8_t index = BLE_APP_CENTRAL_SUPPORT;
    if (app_env.central.w4connect)
    {
        index = app_env.central.w4connect - 1;
    }
    else
    {
        index = app_central_find_by_actv_idx(actv_idx);
    }
    if (index >= BLE_APP_CENTRAL_SUPPORT)
        return;

    LOG_DBG("(%d) state=%x", index, app_env.central.connect[index].state);

    switch(app_env.central.connect[index].state)
    {
        case APP_CENTRAL_SUB_STATE_IDLE:
            break;

        case APP_CENTRAL_SUB_STATE_CREATING:
            app_env.central.connect[index].actv_idx = actv_idx;
            app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_CREATED;
            break;

        case APP_CENTRAL_SUB_STATE_CREATED:
            if (reason)
            {
                app_central_free_node(index);
                app_env.central.w4connect = 0;
            }
            else
            {
                app_central_start_init(index);
            }
            break;

        case APP_CENTRAL_SUB_STATE_STARTING:
            app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_STARTED;
            break;

        case APP_CENTRAL_SUB_STATE_STARTED:
            if (reason != 0)
                app_env.central.connect[index].state = APP_CENTRAL_SUB_STATE_STOPPING;
            break;

        case APP_CENTRAL_SUB_STATE_STOPPING:
        case APP_CENTRAL_SUB_STATE_STOPPED:
            app_central_delete_init(index);
            app_central_free_node(index);
            break;

        case APP_CENTRAL_SUB_STATE_DELETING:
            app_central_free_node(index);
            break;

        default:
            break;
    }
}

/**
 * @brief Find connection information index by connection index
 * 
 * @param conidx: connection index
 * @return uint8_t : connection information index
 */
uint8_t app_central_find_by_conidx(uint8_t conidx)
{
    uint8_t i =0;
    for(i=0; i< BLE_APP_CENTRAL_SUPPORT; i++)
    {
        if (app_env.central.connect[i].conidx == conidx)
            break;
    }
    return i;
}

/**
 * @brief Central module init
 * 
 */
void app_central_init(void)
{
    LOG_VBS_FUNC();
    uint8_t i = 0;
    for(i=0; i< BLE_APP_CENTRAL_SUPPORT; i++)
    {
        app_env.central.connect[i].conidx = 0xFF;
        app_env.central.connect[i].conhdl = 0xFF;
    }
    app_env.central.prf_env.app_task = (ke_task_id_t)(TASK_APP | PERM(PRF_MI, ENABLE));
    app_env.central.prf_env.prf_task = (ke_task_id_t)(TASK_APP | PERM(PRF_MI, ENABLE));
}

/**
 * @brief Update central state
 * 
 * @param opera    : activity type, see @ref enum gapm_actv_type
 * @param actv_idx : activity index
 * @param reason   : operation result reason
 */
void app_central_update_state(uint8_t opera, uint8_t actv_idx, uint8_t reason)
{
    LOG_VBS_FUNC();
    LOG_DBG("opera=%x, index=%x, reason=%x", opera, actv_idx, reason);
    if (opera == GAPM_ACTV_TYPE_SCAN || opera == app_env.central.scan_operation)
    {
        LOG_DBG("GAPM_ACTV_TYPE_SCAN");
        if(opera != GAPM_ACTV_TYPE_SCAN)
            app_env.central.scan_operation = 0;

        app_central_update_scan_state(opera, actv_idx, reason);
    }
    else
    {
        LOG_DBG("GAPM_ACTV_TYPE_INIT");
        app_central_update_init_state(opera, actv_idx, reason);
    }
}

/**
 * @brief Start scan
 * 
 * @return uint8_t : error code, see @ref enum eapp_central_error
 */
uint8_t app_central_scan_start(void)
{
    LOG_VBS_FUNC();
    uint8_t ret = APP_CENTRAL_ERROR_NO_ERROR;
    switch(app_env.central.scan_state)
    {
        case APP_CENTRAL_SUB_STATE_IDLE:
            app_central_create_scan();
            break;
        case APP_CENTRAL_SUB_STATE_CREATED:
            app_central_start_scan();
            break;
        case APP_CENTRAL_SUB_STATE_CREATING:
        case APP_CENTRAL_SUB_STATE_STARTING:
            break;        
        case APP_CENTRAL_SUB_STATE_STARTED:
            ret = APP_CENTRAL_ERROR_SCAN_STARTED;
            break;
        case APP_CENTRAL_SUB_STATE_STOPPING:
        case APP_CENTRAL_SUB_STATE_STOPPED:
        case APP_CENTRAL_SUB_STATE_DELETING:
            app_env.central.scan_todo = SCAN_START;
            break;
        default:
            break;
    }
    return ret;
}

/**
 * @brief Stop scan
 * 
 * @return uint8_t : error code, see @ref enum eapp_central_error
 */
uint8_t app_central_scan_stop(void)
{
    LOG_VBS_FUNC();
    uint8_t ret = APP_CENTRAL_ERROR_NO_ERROR;
    switch(app_env.central.scan_state)
    {
        case APP_CENTRAL_SUB_STATE_IDLE:
            break;
        case APP_CENTRAL_SUB_STATE_CREATING:
        case APP_CENTRAL_SUB_STATE_CREATED:
        case APP_CENTRAL_SUB_STATE_STARTING:
            app_env.central.scan_todo = SCAN_STOP;
            break;
        case APP_CENTRAL_SUB_STATE_STARTED:
            app_central_stop_scan();
            break;
        case APP_CENTRAL_SUB_STATE_STOPPING:
        case APP_CENTRAL_SUB_STATE_STOPPED:
        case APP_CENTRAL_SUB_STATE_DELETING:
            break;
        default:
            break;
    }
    return ret;
}

/**
 * @brief Connect the device of "addr".
 * 
 * @param addr : peer device bluetooth address
 * @return uint8_t : error code, see @ref enum eapp_central_error
 */
uint8_t app_central_connect(struct gap_bdaddr addr)
{
    LOG_VBS_FUNC();

    uint8_t ret = APP_CENTRAL_ERROR_NO_ERROR;

    if (app_env.central.w4connect)
    {
        return APP_CENTRAL_ERROR_CONN_CONNECTING;
    }

    uint8_t index = app_central_find_free();
    if (index < BLE_APP_CENTRAL_SUPPORT)
    {
        LOG_INF("Connect device: %02x:%02x:%02x:%02x:%02x:%02x (%s)",
                addr.addr.addr[5], addr.addr.addr[4], addr.addr.addr[3], 
                addr.addr.addr[2], addr.addr.addr[1], addr.addr.addr[0],
                addr.addr_type==0 ? "Public" : "Random");
        memcpy(&app_env.central.connect[index].addr, &addr, sizeof(struct gap_bdaddr));
        app_central_create_init(index);
        app_env.central.w4connect = index + 1;
    }
    else
    {
        ret = APP_CENTRAL_ERROR_CONN_NO_FREE;
    }

    return ret;
}

/**
 * @brief Disconnect the device of "conidx"
 * 
 * @param conidx : connection index
 * @return uint8_t : error code, see @ref enum eapp_central_error
 */
uint8_t app_central_disconnect(uint8_t conidx)
{
    uint8_t index = app_central_find_by_conidx(conidx);
    if (index < BLE_APP_CENTRAL_SUPPORT)
    {
        app_central_delete_init(index);
        app_central_free_node(index);
        return APP_CENTRAL_ERROR_NO_ERROR;
    }
    return APP_CENTRAL_ERROR_CONN_FAIL;
}

/**
 * @brief Set connection handle
 * 
 * @param conidx : connection index
 * @param conhdl : connection handle
 */
void app_central_set_conn_handle(uint8_t conidx, uint16_t conhdl)
{
    LOG_DBG("Set connection handle(%d)", app_env.central.w4connect);
    uint8_t index = app_env.central.w4connect - 1;
    app_env.central.w4connect = 0;
    app_env.central.connect[index].conidx = conidx;
    app_env.central.connect[index].conhdl = conhdl;
    app_env.central.connect[index].mtu = GAP_MAX_LE_MTU;
    app_env.central.connect[index].tx_len = BLE_MAX_OCTETS;
}

/**
 * @brief Set maximum MTU size
 * 
 * @param conidx : connection index
 * @param mtu    : maximum MTU size
 */
void app_central_set_max_mtu(uint8_t conidx, uint16_t mtu)
{
    uint8_t index = app_central_find_by_conidx(conidx);
    if (index >= BLE_APP_CENTRAL_SUPPORT)
        return;

    LOG_INF("MTU size: %d", mtu);
    app_env.central.connect[index].mtu = mtu;

    // discover gatt service
    prf_disc_svc_all_send(&app_env.central.prf_env, conidx);
}

/**
 * @brief Set Link Layer Tx packet length
 * 
 * @param conidx : connection index
 * @param tx_len : maximum length of Tx
 */
void app_central_set_tx_len(uint8_t conidx, uint16_t tx_len)
{
    uint8_t index = app_central_find_by_conidx(conidx);
    if (index >= BLE_APP_CENTRAL_SUPPORT)
        return;

    LOG_INF("Tx length: %d", tx_len);
    app_env.central.connect[index].tx_len = tx_len;
}

/**
 * @brief Get central scan state
 * 
 * @return uint8_t : scan state, see @ref enum eapp_central_substate
 */
uint8_t app_central_get_scan_state(void)
{
    return app_env.central.scan_state;
}

/**
 * @brief Set scan stopped callback function
 * 
 * @param cb : callback function
 */
void app_central_set_scan_stopped_callback(scan_stopped_callback_t cb)
{
    scan_stopped_callback = cb;
}

#endif /* BLE_APP_CENTRAL_SUPPORT */
